<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\client;

use app\enum\CommonEnum;
use app\enum\TokenEnum;
use app\model\AccountApplyDetailModel;
use app\model\AccountApplyModel;
use app\model\ClientAccountModel;
use app\model\ClientAccountOperationModel;
use app\model\ClientAccountTimeModel;
use app\model\IndustryModel;
use app\model\KsAdvertiserModel;
use app\model\mysql\OeAdvertiserInfoModel;
use app\model\PortModel;
use app\service\BaseService;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use think\facade\Db;
use think\Model;

final class AccountService extends BaseService
{
    /**
     * 查询账户是否投放中。
     * @param int $accountId 账户表id
     * @param int $date 日期
     * @throws DbException
     */
    public static function isPuttingAccount(int $accountId = 0, int $date = 0): bool
    {
        $where = [
            ['account_id', '=', $accountId],
            ['start_date', '<=', $date],
            ['end_date', '>=', $date],
        ];
        return (new ClientAccountTimeModel())->where($where)->count('id') > 0;
    }

    /**
     * 获取账户模型.
     * @param int $accountId 账户表id
     * @param string $advertiserId 账户id
     * @return null|array|ClientAccountModel|mixed|Model
     */
    public static function getAccountModel(int $accountId = 0, string $advertiserId = '')
    {
        $where = [];
        if ($accountId) {
            $where[] = ['id', '=', $accountId];
        }
        if ($advertiserId) {
            $where[] = ['advertiser_id', '=', $advertiserId];
        }
        return (new ClientAccountModel())->where($where)->findOrEmpty();
    }

    /**
     * 获取账户模型列表.
     * @param int $mediaId 媒体id
     * @param int $status 状态 1正常  2停投
     * @return array|ClientAccountModel[]|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getAccountList(int $mediaId = 0, int $status = 0, int $authValid = 0)
    {
        $where = [];
        if ($mediaId) {
            $where[] = ['media_id', '=', $mediaId];
        }
        if ($status) {
            $where[] = ['status', '=', $status];
        }
        if ($authValid) {
            $where[] = ['auth_valid', '=', $authValid];
        }
        return (new ClientAccountModel())->where($where)->select();
    }

    /**
     * 修改账户最新数据日期.
     * @param ClientAccountModel $model 账户模型
     * @param int $date 日期
     */
    public static function synAccountCostTime(ClientAccountModel $model, int $date = 0): bool
    {
        if (! $model->getKey()) {
            return self::setError('同步账户消耗最新日期失败：账户不存在');
        }
        if (! $date) {
            return self::setError('同步账户消耗最新日期失败：日期不能为空');
        }
        $model->setAttr('cost_date', $date);
        return $model->save();
    }

    /**
     * 查询所有有效账户。
     * @param int $date 日期
     * @param int $mediaId 媒体id
     */
    public static function getPuttingAccount(int $date = 0, int $mediaId = 0): array
    {
        $where = [
            ['start_date', '<=', $date],
            ['end_date', '>=', $date],
        ];
        if ($mediaId) {
            $where[] = ['media_id', '=', $mediaId];
        }

        return (new ClientAccountTimeModel())->where($where)->group('account_id')->column('account_id');
    }

    /**
     * 查询所有有效账户按消耗从高往低。
     * @param int $date 日期
     * @param int $mediaId 媒体id
     * @deprecated
     */
    public static function getSortPuttingAccount(int $date = 0, int $mediaId = 0): array
    {
        $sql = "SELECT
                    t.account_id 
                FROM
                    habo_client_account_time AS t
                    INNER JOIN habo_client_account AS a ON t.account_id = a.id 
                WHERE
                    t.start_date <= {$date} AND t.end_date >= {$date} 
                    AND t.media_id = {$mediaId} 
                    AND a.auth_valid = " . ClientAccountModel::STATUS_ENABLE . ' 
                GROUP BY
                    t.account_id 
                ORDER BY
                    a.cost_sort DESC';

        return array_column(Db::query($sql), 'account_id');
    }

    /**
     * 查询所有有效账户。
     * @param array $params 条件
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getTimeAccount(array $params = [])
    {
        $where = [];
        if (! empty($params['end_date'])) {
            $where[] = ['end_date', '=', $params['end_date']];
        }
        if (! empty($params['start_date'])) {
            $where[] = ['start_date', '=', $params['start_date']];
        }
        if (! empty($params['media_id'])) {
            $where[] = ['media_id', '=', $params['media_id']];
        }
        if (! empty($params['client_id'])) {
            $where[] = ['client_id', '=', $params['client_id']];
        }
        return (new ClientAccountTimeModel())->where($where)->select();
    }

    /**
     * 修改account_time表end_date字段.
     * @param ClientAccountTimeModel $model 模型
     * @param int $endDate 结束日期
     */
    public static function updateTimeAccount(ClientAccountTimeModel $model, int $endDate = 0): bool
    {
        if ($endDate < $model->getAttr('start_date')) {
            return self::setError('结束日期不能小于开始日期');
        }
        $model->setAttr('end_date', $endDate);
        return $model->save();
    }

    /**
     * 获取账户token.
     * @param mixed $advertiserId 账户id
     * @param mixed $type
     * @param mixed $sort
     */
    public static function getToken(int $mediaId, $advertiserId, $type = '', $sort = 0)
    {
        $token = '';
        $redis = Cache::store('redis')->handler();
        if ($mediaId == CommonEnum::QQ_MEDIA) {
            // 广点通媒体
            if ($type && ! empty(TokenEnum::QQ_TOKEN_API_KEY_ARR[$type])) {
                // 广点通token根据类型返回
                $redisKey = TokenEnum::QQ_TOKEN_API_KEY_ARR[$type]['redis_key'];
                // 一定次数拿不到退出
                $num = 10;
                for ($i = 0; $i < $num; ++$i) {
                    $isHas = $redis->lPop($redisKey);
                    if (! $isHas) {
                        echo 'key:' . $redisKey . '，' . $advertiserId . '获取token次数：' . $i . PHP_EOL;
                        usleep(rand(800000, 1500000));  // 0.8m-1.5m
                        continue;
                    }
                    $token = $redis->get($advertiserId . TokenEnum::QQ_TOKEN);
                    break;
                }
            }
        } else {
            // 快手&巨量媒体
            // 拿账户和token 的关系信息
            $relationKey = TokenEnum::TOKEN_ADV_REDIS_KEY . $advertiserId;
            $tokenLists = $redis->get($relationKey);
            if ($tokenLists) {
                $tokenArr = explode(',', $tokenLists);
                if ($type == 1 && $mediaId == CommonEnum::OE_MEDIA) {
                    // 批量搭建的，拿最后一个,日报时报专用
                    $tokenId = array_pop($tokenArr);
                } elseif ($sort == 1) {
                    if (count($tokenArr) > 1) {
                        // 拿倒数第二个，搭建专用
                        $tokenId = $tokenArr[count($tokenArr) - 2];
                    } else {
                        // 拿最后一个
                        $tokenId = array_pop($tokenArr);
                    }
                } else {
                    // 随机取一个
                    $randNum = rand(0, count($tokenArr) - 1);
                    $tokenId = $tokenArr[$randNum];
                }
                $tokenKey = TokenEnum::getTokenRedisKey(intval($mediaId), intval($tokenId));
                // 一定次数拿不到退出
                $num = 10;
                for ($i = 0; $i < $num; ++$i) {
                    $redisKey = $tokenKey;
                    $token = $redis->lPop($redisKey);
                    if (! $token) {
                        usleep(rand(800000, 1500000));  // 0.8m-1.5m
                        continue;
                    }
                    break;
                }
            }
        }
        return $token;
    }

    /**
     * 获取快手user-id。
     * @param string $advertiserId 账户id
     * @return mixed
     * @deprecated
     */
    public static function getKsUserId(string $advertiserId = '')
    {
        $where = [
            ['advertiser_id', '=', $advertiserId],
        ];
        return (new KsAdvertiserModel())->where($where)->value('user_id');
    }

    /**
     * 获取账户开户信息.
     * @param string $advertiserId 广告主id
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getAccountApplyInfo(string $advertiserId): array
    {
        $applyDetailData = (new AccountApplyDetailModel())->where('advertiser_id', $advertiserId)->find();
        if (! $applyDetailData) {
            return [];
        }
        return (new AccountApplyModel())->where('id', $applyDetailData['apply_id'])->find()->toArray();
    }

    /**
     * 获取行业名.
     * @param int $id 行业id
     * @return mixed
     */
    public static function getIndustryName(int $id = 0)
    {
        return (new IndustryModel())->where('id', $id)->value('industry_name');
    }

    /**
     * 获取账户运营数据.
     * @param string $advertiserId 广告主id
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getOperation(string $advertiserId = '')
    {
        return (new ClientAccountOperationModel())->where('advertiser_id', $advertiserId)->find();
    }

    /**
     * 获取账户行业.
     * @param string $advertiserId 账户id
     * @param int $mediaId 媒体id
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getAccountIndustry(string $advertiserId = '', int $mediaId = 0): array
    {
        $data = [];
        if ($mediaId == CommonEnum::OE_MEDIA) {
            $info = (new OeAdvertiserInfoModel())->where('advertiser_id', $advertiserId)->find();
            $data = [
                'industry_one' => $info['first_industry_name'] ?? '',
                'industry_two' => $info['second_industry_name'] ?? '',
            ];
        } elseif ($mediaId == CommonEnum::KS_MEDIA) {
            $info = (new KsAdvertiserModel())->where('advertiser_id', $advertiserId)->find();
            $data = [
                'industry_one' => $info['primary_industry_name'] ?? '',
                'industry_two' => $info['industry_name'] ?? '',
            ];
        }
        return $data;
    }

    /**
     * 获取端口名.
     * @param int $portId 端口id
     * @return string
     */
    public static function getPortName(int $portId): string
    {
        if ($portId == -1) {
            return '巨量客户';
        }
        if ($portId == -2) {
            return '快手客户';
        }
        $port = (new PortModel())->alias('a')
            ->join(['habo_provider' => 'b'], 'a.provider_id=b.id')
            ->join(['habo_subject' => 'c'], 'a.subject_id=c.id')
            ->join(['habo_media' => 'd'], 'a.media_id=d.id')
            ->where('a.id', $portId)
            ->field('b.provider_name,c.abbreviation,d.media_name')
            ->find();
        $str = '';
        if (! empty($port['media_name'])) {
            $str .= $port['media_name'];
        }
        if (! empty($port['abbreviation'])) {
            $str .= '/' . $port['abbreviation'];
        }
        if (! empty($port['provider_name'])) {
            $str .= '/' . $port['provider_name'];
        }
        return $str;
    }
}
